home *** CD-ROM | disk | FTP | other *** search
/ QRZ! Ham Radio 8 / QRZ Ham Radio Callsign Database - Volume 8.iso / pc / files / t_unix / j109lxa4.tar / dialer.c < prev    next >
C/C++ Source or Header  |  1994-06-04  |  13KB  |  620 lines

  1. /* Automatic SLIP/PPP line dialer.
  2.  *
  3.  * Copyright 1991 Phil Karn, KA9Q
  4.  *
  5.  *    Mar '91    Bill Simpson & Glenn McGregor
  6.  *        completely re-written;
  7.  *        human readable control file;
  8.  *        includes wait for string, and speed sense;
  9.  *        dials immediately when invoked.
  10.  *    May '91 Bill Simpson
  11.  *        re-ordered command line;
  12.  *        allow dial only;
  13.  *        allow inactivity timeout without ping.
  14.  *    Sep '91 Bill Simpson
  15.  *        Check known DTR & RSLD state for redial decision
  16.  *
  17.  * Mods by PA0GRI (newsession parameters)
  18.  *
  19.  * Mods by KF8NH:  iffailed, begin/end
  20.  */
  21. #include <stdio.h>
  22. #include <ctype.h>
  23. #include "global.h"
  24. #include "config.h"
  25. #include "mbuf.h"
  26. #include "timer.h"
  27. #include "proc.h"
  28. #include "iface.h"
  29. #include "netuser.h"
  30. #include "commands.h"
  31. #ifdef UNIX
  32. #include "unixasy.h"
  33. #else
  34. #include "i8250.h"
  35. #endif
  36. #include "asy.h"
  37. #include "tty.h"
  38. #include "session.h"
  39. #include "socket.h"
  40. #include "cmdparse.h"
  41. #include "devparam.h"
  42. #include "icmp.h"
  43. #include "files.h"
  44. #include "main.h"
  45. #include "trace.h"
  46.  
  47. #define MIN_INTERVAL    5L
  48. #define MAXDEPTH    8
  49.  
  50. static int Failmode = 0;
  51. static char Failed;
  52. static char Depth;
  53. static char Skip[MAXDEPTH];
  54. static char SkipOverride;
  55. static char OverrideDepth;
  56.  
  57. static int redial __ARGS((struct iface *ifp,char *file));
  58.  
  59. static int dodial_nothing    __ARGS((int argc,char *argv[],void *p));
  60. static int dodial_begin        __ARGS((int argc,char *argv[],void *p));
  61. static int dodial_control    __ARGS((int argc,char *argv[],void *p));
  62. static int dodial_end        __ARGS((int argc,char *argv[],void *p));
  63. static int dodial_exit        __ARGS((int argc,char *argv[],void *p));
  64. static int dodial_failmode    __ARGS((int argc,char *argv[],void *p));
  65. static int dodial_iffail    __ARGS((int argc,char *argv[],void *p));
  66. static int dodial_ifok        __ARGS((int argc,char *argv[],void *p));
  67. static int dodial_send        __ARGS((int argc,char *argv[],void *p));
  68. static int dodial_speed        __ARGS((int argc,char *argv[],void *p));
  69. static int dodial_status    __ARGS((int argc,char *argv[],void *p));
  70. static int dodial_wait        __ARGS((int argc,char *argv[],void *p));
  71.  
  72.  
  73. static struct cmds dial_cmds[] = {
  74.     "",        dodial_nothing, 0, 0, "",
  75.     "begin",    dodial_begin,    0, 1, "begin",
  76.     "control",    dodial_control,    0, 2, "control up | down",
  77.     "end",        dodial_end,    0, 1, "end",
  78.     "exit",        dodial_exit,    0, 1, "exit",
  79.     "failmode",    dodial_failmode,0, 2, "failmode on | off",
  80.     "iffail",    dodial_iffail,    0, 2, "iffail \"command\"",
  81.     "ifok",        dodial_ifok,    0, 2, "ifok \"command\"",
  82.     "send",        dodial_send,    0, 2,
  83.     "send \"string\" [<milliseconds>]",
  84.     "speed",    dodial_speed,    0, 2, "speed <bps>",
  85.     "status",    dodial_status, 0, 2, "status up | down",
  86.     "wait",        dodial_wait,    0, 2,
  87.     "wait <milliseconds> [ \"string\" [speed] ]",
  88.     NULLCHAR,    NULLFP((int,char**,void*)), 0, 0, "Unknown command",
  89. };
  90.  
  91.  
  92. /* dial <iface> <filename> [ <seconds> [ <pings> [<hostid>] ] ]
  93.  *    <iface>        must be asy type
  94.  *    <filename>    contains commands which are executed.
  95.  *            missing: kill outstanding dialer.
  96.  *    <seconds>    interval to check for activity on <iface>.
  97.  *    <pings>     number of missed pings before redial.
  98.  *    <hostid>    interface to ping.
  99.  */
  100. int
  101. #ifdef PROTOTYPES
  102. dodialer(int argc,char **argv,void *p)
  103. #else
  104. dodialer(argc,argv,p)
  105. int argc;
  106. char *argv[];
  107. void *p;
  108. #endif
  109. {
  110.     struct iface *ifp;
  111.     struct asy *ap;
  112.     int32 interval = 0L;        /* in seconds */
  113.     int32 last_wait = 0L;
  114.     int32 target = 0L;
  115.     int pings = 0;
  116.     int countdown;
  117.     char *filename;
  118.     char *ifn;
  119.     int result;
  120.     int s;
  121.  
  122.     if((ifp = if_lookup(argv[1])) == NULLIF){
  123.         tprintf(Badinterface,argv[1]);
  124.         return 1;
  125.     }
  126.     if( ifp->dev >= ASY_MAX || Asy[ifp->dev].iface != ifp ){
  127.         tprintf("Interface %s not asy port\n",argv[1]);
  128.         return 1;
  129.     }
  130.  
  131.     if(ifp->supv != NULLPROC){
  132.         while ( ifp->supv != NULLPROC ) {
  133.             alert(ifp->supv, EABORT);
  134.             pwait(NULL);
  135.         }
  136.         tprintf("dialer terminated on %s\n",argv[1]);
  137.     }
  138.  
  139.     if ( argc < 3 ) {
  140.         /* just terminating */
  141.         return 0;
  142.     }
  143.  
  144.     chname( Curproc, ifn = if_name( ifp, " dialer" ) );
  145.     free( ifn );
  146.     filename = rootdircat(argv[2]);
  147.  
  148.     /* handle minimal command (just thru filename) */
  149.     if ( argc < 4 ) {
  150.         /* just dialing */
  151.         result = redial(ifp, filename);
  152.  
  153.         if ( filename != argv[2] )
  154.             free(filename);
  155.         return result;
  156.  
  157.     /* get polling interval (arg 3) */
  158.     } else if ( (interval = atol(argv[3])) <= MIN_INTERVAL ) {
  159.         tprintf("interval must be > %ld seconds\n", MIN_INTERVAL);
  160.         return 1;
  161.     }
  162.  
  163.     /* get the number of pings before redialing (arg 4) */
  164.     if ( argc < 5 ) {
  165.     } else if ( (pings = atoi(argv[4])) <= 0 ){
  166.         tprintf("pings must be > 0\n");
  167.         return 1;
  168.     }
  169.  
  170.     /* retrieve the host name (arg 5) */
  171.     if ( argc < 6 ) {
  172.     } else if ( (target = resolve(argv[5])) == 0L ) {
  173.         tprintf(Badhost,argv[5]);
  174.         return 1;
  175.     }
  176.  
  177.     countdown = pings;
  178.     ifp->supv = Curproc;
  179.     ap = &Asy[ ifp->dev ];
  180.  
  181.     while ( !main_exit ) {
  182.         int32 wait_for = interval;
  183.  
  184.         /*
  185.          * N.B. Eventually, when the rest of this is stable, I will
  186.          * look into supporting DTR and RTS.  For now, it's enough to
  187.          * just have the code work.
  188.          */
  189. #ifndef UNIX
  190.         if ( ap->dtr_usage == FOUND_DOWN
  191.          ||  ap->dtr_usage == MOVED_DOWN
  192.          ||  ap->rlsd_line_control == MOVED_DOWN ) {
  193.             /* definitely down */
  194.             if ( redial(ifp,filename) < 0 )
  195.                 break;
  196.         } else
  197. #endif
  198.         if ( ifp->lastrecv >= last_wait ) {
  199.             /* got something recently */
  200.             wait_for -= secclock() - ifp->lastrecv;
  201.             countdown = pings;
  202.         } else if ( countdown < 1 ) {
  203.             /* we're down, or host we ping is down */
  204.             if ( redial(ifp,filename) < 0 )
  205.                 break;
  206.             countdown = pings;
  207.         } else if ( target != 0L
  208.            && (s = socket(AF_INET,SOCK_RAW,ICMP_PTCL)) != -1 ) {
  209.             pingem(s,target,0,(int16)s,0);
  210.             close_s(s);
  211.             countdown--;
  212.         } else if ( ifp->echo != NULLFP((struct iface*,struct mbuf*))){
  213.             (*ifp->echo)(ifp,NULLBUF);
  214.             countdown--;
  215.         }
  216.  
  217.         last_wait = secclock();
  218.         if ( wait_for != 0L ) {
  219.             alarm( wait_for * 1000L );
  220.             if ( pwait( &(ifp->supv) ) == EABORT )
  221.                 break;
  222.             alarm(0L);        /* clear alarm */
  223.         }
  224.     }
  225.  
  226.     if ( filename != argv[2] )
  227.         free(filename);
  228.     ifp->supv = NULLPROC;    /* We're being terminated */
  229.     return 0;
  230. }
  231.  
  232.  
  233. /* execute dialer commands
  234.  * returns: -1 fatal error, 0 OK, 1 try again
  235.  */
  236. static int
  237. redial( ifp, file )
  238. struct iface *ifp;
  239. char *file;
  240. {
  241.     char *inbuf, *intmp;
  242.     FILE *fp;
  243.     int (*rawsave) __ARGS((struct iface *,struct mbuf *));
  244.     struct session *sp;
  245.     int result = 0;
  246.     int save_input = Curproc->input;
  247.     int save_output = Curproc->output;
  248.  
  249.     if((fp = fopen(file,READ_TEXT)) == NULLFILE){
  250.         tprintf("redial: can't read %s\n",file);
  251.         return -1;    /* Causes dialer proc to terminate */
  252.     }
  253.     /* Save output handler and temporarily redirect output to null */
  254.     if(ifp->raw == bitbucket){
  255.         tprintf("redial: tip or dialer already active on %s\n",ifp->name);
  256.         return -1;
  257.     }
  258.  
  259.     /* allocate a session descriptor */
  260.     if ( (sp = newsession( ifp->name, DIAL, 0 )) == NULLSESSION ) {
  261.         tputs(TooManySessions);
  262.         return 1;
  263.     }
  264.     tprintf( "Dialing on %s\n\n", ifp->name );
  265.  
  266.     /* Save output handler and temporarily redirect output to null */
  267.     rawsave = ifp->raw;
  268.     ifp->raw = bitbucket;
  269.  
  270.     /* Suspend the packet input driver. Note that the transmit driver
  271.      * is left running since we use it to send buffers to the line.
  272.      */
  273.     suspend(ifp->rxproc);
  274.  
  275. #ifdef notdef
  276. tprintf("rlsd: 0x%02x, dtr: 0x%02x\n",
  277.     Asy[ifp->dev].rlsd_line_control,
  278.     Asy[ifp->dev].dtr_usage );
  279. #endif
  280.  
  281.     Failed = 0;
  282.     Depth = 0;
  283.     Skip[0] = 0;
  284.     SkipOverride = -1;
  285.  
  286.     inbuf = mallocw(BUFSIZ);
  287.     intmp = mallocw(BUFSIZ);
  288.     while ( fgets( inbuf, BUFSIZ, fp ) != NULLCHAR ) {
  289.         strcpy(intmp,inbuf);
  290.         rip( intmp );
  291.         log( -1, "%s dialer: %s", ifp->name, intmp );
  292.         if( (result = cmdparse(dial_cmds,inbuf,ifp)) != 0 ){
  293.             if (Failmode)
  294.                 Failed = 1;
  295.             else
  296.             {
  297.             tprintf("input line: %s",intmp);
  298.             break;
  299.         }
  300.     }
  301.         else
  302.             Failed = 0;
  303.         if (Depth == -1)
  304.             break;
  305.         if (SkipOverride != -1)
  306.         {
  307.             Skip[OverrideDepth] = SkipOverride;
  308.             SkipOverride = -1;
  309.         }
  310.     }
  311.     if (Depth > 0)
  312.         tprintf("Warning: %d unmatched `begin's in command file\n", Depth);
  313.     free(inbuf);
  314.     free(intmp);
  315.     fclose(fp);
  316.  
  317.     if ( result == 0 ) {
  318.         ifp->lastsent = ifp->lastrecv = secclock();
  319.     }
  320.  
  321.     ifp->raw = rawsave;
  322.     resume(ifp->rxproc);
  323.     tprintf( "\nDial %s complete\n", ifp->name );
  324.  
  325.     /* Wait for awhile, so the user can read the screen,
  326.      * AND to give it time to send some packets on the new connection!
  327.      */
  328.     /* ten seconds is an AWFULLY long time... */
  329.     pause( 2000L );
  330.     freesession( sp );
  331.     Curproc->input = save_input;
  332.     Curproc->output = save_output;
  333.     return result;
  334. }
  335.  
  336.  
  337. static int
  338. dodial_control(argc,argv,p)
  339. int argc;
  340. char *argv[];
  341. void *p;
  342. {
  343.     struct iface *ifp = p;
  344.     int param;
  345.  
  346.     if (Skip[Depth])
  347.         return 0;
  348.  
  349.     tprintf("control %s %ld\n", argv[1], atol(argv[2]));
  350.     if ( ifp->ioctl == NULL )
  351.         return -1;
  352.  
  353.     if ( (param = devparam( argv[1] )) == -1 )
  354.         return -1;
  355.  
  356.     (*ifp->ioctl)( ifp, param, TRUE, atol( argv[2] ) );
  357.     return 0;
  358. }
  359.  
  360.  
  361. static int
  362. dodial_send(argc,argv,p)
  363. int argc;
  364. char *argv[];
  365. void *p;
  366. {
  367.     struct iface *ifp = p;
  368.     struct mbuf *bp;
  369.  
  370.     if (Skip[Depth])
  371.         return 0;
  372.  
  373.     tprintf("send <%s>\n", argv[1]);
  374.     if(argc > 2){
  375.         /* Send characters with inter-character delay
  376.          * (for dealing with prehistoric Micom switches that
  377.          * can't take back-to-back characters...yes, they
  378.          * still exist.)
  379.          */
  380.         char *cp;
  381.         int32 cdelay = atol(argv[2]);
  382.  
  383.         for(cp = argv[1];*cp != '\0';cp++){
  384.             bp = qdata(cp,1);
  385.             asy_send(ifp->dev,bp);
  386.             pause(cdelay);
  387.         }
  388.     } else {
  389.         bp = qdata( argv[1], (int16)strlen(argv[1]) );
  390.  
  391.         if (ifp->trace & IF_TRACE_RAW)
  392.             raw_dump( ifp, IF_TRACE_OUT, bp );
  393.         asy_send( ifp->dev, bp );
  394.     }
  395.     return 0;
  396. }
  397.  
  398.  
  399. static int
  400. dodial_speed(argc,argv,p)
  401. int argc;
  402. char *argv[];
  403. void *p;
  404. {
  405.     struct iface *ifp = p;
  406.  
  407.     if (Skip[Depth])
  408.         return 0;
  409.  
  410.     if ( argc < 2 ) {
  411.         tprintf( "current speed = %lu bps\n", Asy[ifp->dev].speed );
  412.         return 0;
  413.     }
  414.     tprintf("speed %ld\n", atol(argv[1]));
  415.     return asy_speed( ifp->dev, (int16)atol( argv[1] ) );
  416. }
  417.  
  418.  
  419. static int
  420. dodial_status(argc,argv,p)
  421. int argc;
  422. char *argv[];
  423. void *p;
  424. {
  425.     struct iface *ifp = p;
  426.     int param;
  427.  
  428.     if (Skip[Depth])
  429.         return 0;
  430.  
  431.     if ( ifp->iostatus == NULL )
  432.         return -1;
  433.  
  434.     if ( (param = devparam( argv[1] )) == -1 )
  435.         return -1;
  436.  
  437.     (*ifp->iostatus)( ifp, param, atol( argv[2] ) );
  438.     return 0;
  439. }
  440.  
  441.  
  442. static int
  443. dodial_wait(argc,argv,p)
  444. int argc;
  445. char *argv[];
  446. void *p;
  447. {
  448.     struct iface *ifp = p;
  449.     register int c = -1;
  450.  
  451.     if (Skip[Depth])
  452.         return 0;
  453.  
  454.     alarm( atol( argv[1] ) );
  455.  
  456.     if ( argc == 2 ) {
  457.         tprintf("wait %ld\nimsg <", atol(argv[1]));
  458.         tflush();
  459.         while ( (c = get_asy(ifp->dev)) != -1 ) {
  460.             tputc( c &= 0x7F );
  461.             tflush();
  462.         }
  463.         alarm( 0L );
  464.         tprintf(">\n");
  465.         return 0;
  466.     } else {
  467.         register char *cp = argv[2];
  468.  
  469.         tprintf("waitfor <%s>\nimsg <", argv[2]);
  470.         tflush();
  471.         while ( *cp != '\0'  &&  (c = get_asy(ifp->dev)) != -1 ) {
  472.             tputc( c &= 0x7F );
  473.             tflush();
  474.  
  475.             if (*cp++ != c) {
  476.                 cp = argv[2];
  477.             }
  478.         }
  479.  
  480.         if ( argc > 3 ) {
  481.             if ( stricmp( argv[3], "speed" ) == 0 ){
  482.                 int16 speed = 0;
  483.  
  484.                 while ( (c = get_asy(ifp->dev)) != -1 ) {
  485.                     tputc( c &= 0x7F );
  486.                     tflush();
  487.  
  488.                     if ( isdigit(c) ) {
  489.                         speed *= 10;
  490.                         speed += c - '0';
  491.                     } else {
  492.                         alarm( 0L );
  493.                         tprintf("> ok\n");
  494.                         return asy_speed( ifp->dev, speed );
  495.                     }
  496.                 }
  497.             } else {
  498.                 tprintf("> bad command\n");
  499.                 return -1;
  500.             }
  501.         }
  502.     }
  503.     alarm( 0L );
  504.     tprintf("> %s\n", (c == -1? "failed": "ok"));
  505.     return ( c == -1 );
  506. }
  507.  
  508.  
  509. static int
  510. dodial_failmode(argc, argv, p)
  511.     int argc;
  512.     char **argv;
  513.     void *p;
  514. {
  515.     if (Skip[Depth])
  516.     return 0;
  517.     tprintf("failmode %s\n", argv[1]);
  518.     return setbool(&Failmode, "Continue on dial command failure", argc, argv);
  519. }
  520.  
  521. static int
  522. dodial_iffail(argc, argv, p)
  523.     int argc;
  524.     char **argv;
  525.     void *p;
  526. {
  527.     if (!Skip[Depth])
  528.     {
  529.     if (SkipOverride == -1)
  530.     {
  531.         SkipOverride = Skip[Depth];
  532.         OverrideDepth = Depth;
  533.     }
  534.     Skip[Depth] = !Failed;
  535.     }
  536.     return cmdparse(dial_cmds, argv[1], p);
  537. }
  538.  
  539. static int
  540. dodial_ifok(argc, argv, p)
  541.     int argc;
  542.     char **argv;
  543.     void *p;
  544. {
  545.     if (!Skip[Depth])
  546.     {
  547.     if (SkipOverride == -1)
  548.     {
  549.         SkipOverride = Skip[Depth];
  550.         OverrideDepth = Depth;
  551.     }
  552.     Skip[Depth] = Failed;
  553.     }
  554.     return cmdparse(dial_cmds, argv[1], p);
  555. }
  556.  
  557. static int
  558. dodial_begin(argc, argv, p)
  559.     int argc;
  560.     char **argv;
  561.     void *p;
  562. {
  563.     if (Depth == MAXDEPTH)
  564.     {
  565.     Depth = -1;
  566.     tprintf("Blocks nested too deep\n");
  567.     return -1;
  568.     }
  569.     if (!Skip[Depth])
  570.     tprintf("begin\n");
  571.     Skip[Depth + 1] = Skip[Depth];
  572.     Depth++;
  573.     return 0;
  574. }
  575.  
  576. static int
  577. dodial_end(argc, argv, p)
  578.     int argc;
  579.     char **argv;
  580.     void *p;
  581. {
  582.     if (!Skip[Depth])
  583.     tprintf("end\n");
  584.     if (Depth-- == 0)
  585.     {
  586.     tprintf("`end' without `begin'\n");
  587.     return -1;
  588.     }
  589.     return 0;
  590. }
  591.  
  592. static int
  593. dodial_exit(argc, argv, p)
  594.     int argc;
  595.     char **argv;
  596.     void *p;
  597. {
  598.     if (Skip[Depth])
  599.     return 0;
  600.     if (argc > 1)
  601.     tprintf("exit %d\n", atoi(argv[1]));
  602.     else
  603.     tprintf("exit\n");
  604.     Depth = -1;
  605.     return (argc > 1? atoi(argv[1]): Failed);
  606. }
  607.  
  608. /*
  609.  * cmdparse sends blank lines to the first command, sigh
  610.  */
  611.  
  612. static int
  613. dodial_nothing(argc, argv, p)
  614.     int argc;
  615.     char **argv;
  616.     void *p;
  617. {
  618.     return 0;
  619. }
  620.